This is the accompanying Notebook for my project 1 results/code. My project seeked out whether the sentiment of a school changed over time. My hypothesis was that for a given school, the sentiment should not change between their publications over time. The underlying idea was that a school has a set of thoughts that they follow, and that they wouldn’t change that drastically over time since any large shifts would probably sprout a new school of thought.
Step 0 - Initialize the environment
packages.used=c("dplyr", "tidyverse", "tm", "wordcloud", "RColorBrewer",
"tidytext", "Rcpp", "textclean", "ggalt", "ggplot2", "gridExtra")
# check packages that need to be installed.
packages.needed=setdiff(packages.used,
intersect(installed.packages()[,1],
packages.used))
# install additional packages
if(length(packages.needed)>0){
install.packages(packages.needed, dependencies = TRUE,
repos='http://cran.us.r-project.org')
}
library(dplyr)
library(tidyverse)
library(tm)
library(wordcloud)
library(RColorBrewer)
library(tidytext)
library(Rcpp)
library(textclean)
library(ggalt)
library(ggplot2)
library(gridExtra)
setwd("M:/Documents/CU Coursework/STAT5243 Applied Data Science/Projects/Fall2021-Project1-AryaAyati")
The notebook was prepared with the following environmental settings.
print(R.version)
_
platform x86_64-w64-mingw32
arch x86_64
os mingw32
system x86_64, mingw32
status
major 4
minor 1.1
year 2021
month 08
day 10
svn rev 80725
language R
version.string R version 4.1.1 (2021-08-10)
nickname Kick Things
Step 2 - Text processing
sentenceCorpus <- Corpus(VectorSource(data.raw$sentence_lowered))
sentenceCorpus<-tm_map(sentenceCorpus, removeWords, stopwords("english"))
transformation drops documents
sentenceCorpus<-tm_map(sentenceCorpus, removeWords, character(0))
transformation drops documents
sentenceCorpus<-tm_map(sentenceCorpus, removePunctuation)
transformation drops documents
sentenceCorpus<-tm_map(sentenceCorpus, stripWhitespace)
transformation drops documents
tdm <- TermDocumentMatrix(sentenceCorpus)
tdm = removeSparseTerms(tdm, 0.99)
tdm.tidy = tidytext::tidy(tdm)
tdm.overall=summarise(group_by(tdm.tidy, term), sum(count))
Step 3 - Overall wordcloud inspection
Generating a wordcloud of the Document Term Matrix cleaned of stopwords and other non-word characters yielded the following:
Overall, the terms seem normal for philosophical texts and confirm that we have appropriate data. Generating another wordcloud using TF-IDF yielded the following:
The TF-IDF wordcloud is pretty similar to the original which leads me to believe that something went wrong along the way. Luckily, this was primarily an excercise to explore the format of the data and is not relevant to the hypothesis testing.
Step 4 - Grouping publications by year to analyze regressability
Plotting the publications over time to see if there are enough datapoints between the schools to make the analysis worthwhile yields: 
Filtering the schools of thought to those with 3 or more publications - so that a regression is nontrivial - yielded the following plot:
From here, most of the remaining schools should have enough datapoints to attempt to fit linear models to them and determine if nonzero coefficients are significant or not.
Step 5 - Loop through the remaining schools and perform regressions to test hypothesis
#Sentiment Analysis per school using helper function:
PerSchoolSentimentAnalysis <- function(sch, data.gttSenti) {
schooldata.raw = data.gttSenti[data.gttSenti$school==sch,]
years = unique(schooldata.raw$original_publication_date)
schooldata.Senti = data.frame(matrix(ncol = 5, nrow = 0))
colnames(schooldata.Senti) <- c("year", "negative", "positive", "sentiment", "netSenti")
for (i in years){
#per publication sentiment
schooldata.temptxt = schooldata.raw %>%
filter(original_publication_date == i)
schooldata.yrTokens = data_frame(tokens = schooldata.temptxt$tokenized_txt) %>%
unnest_tokens(word, tokens)
#reference https://cran.r-project.org/web/packages/tidytext/vignettes/tidytext.html
schooldata.tmpSenti = schooldata.yrTokens %>%
inner_join(get_sentiments("bing")) %>%
count(sentiment) %>%
spread(sentiment, n, fill = 0) %>%
mutate(sentiment = positive / (positive + negative), netSenti = positive-negative)
schooldata.yrSenti = cbind(data_frame(year = i), schooldata.tmpSenti)
schooldata.Senti = rbind(schooldata.Senti, schooldata.yrSenti)
}
percLM = lm(sentiment~year, data = schooldata.Senti)
netLM = lm(netSenti~year, data = schooldata.Senti)
percPlot = ggplot(data = schooldata.Senti, aes(x=year, y=sentiment)) +
geom_point(color='blue') +
geom_smooth(method = "lm", se = TRUE, formula = y~x)+
labs(subtitle = paste("Adj R2 = ",signif(summary(percLM)$adj.r.squared, 5),
"Intercept =",signif(percLM$coef[[1]],5 ),
" Slope =",signif(percLM$coef[[2]], 5),
" P =",signif(summary(percLM)$coef[2,4], 5)))+
ggtitle(paste("Sentiment by Year for", str_to_title(sch)))+
xlab("Year")+
ylab("Positive Sentiment Percent")+
theme(plot.title = element_text(hjust = 0.5))
netPlot = ggplot(data = schooldata.Senti, aes(x=year, y=netSenti)) +
geom_point(color='blue') +
geom_smooth(method = "lm", se = TRUE, formula = y~x)+
labs(subtitle = paste("Adj R2 = ",signif(summary(netLM)$adj.r.squared, 5),
"Intercept =",signif(netLM$coef[[1]],5 ),
" Slope =",signif(netLM$coef[[2]], 5),
" P =",signif(summary(netLM)$coef[2,4], 5)))+
ggtitle(paste("Sentiment by Year for", str_to_title(sch)))+
xlab("Year")+
ylab("Net Positive Sentiment")+
theme(plot.title = element_text(hjust = 0.5))
png(paste("figs/", sch, "_plots.png", sep=""), units="in", width=12, height=5, res=600)
grid.arrange(percPlot, netPlot, ncol=2)
dev.off()
#Insert plots here in markdown
#save regression summaries for later
schooldata.yrlm = cbind(data_frame(school = sch),
data_frame(list(percLM)),
data_frame(list(netLM)))
colnames(schooldata.yrlm) <- c("school", "percentLM", "netLM")
return(schooldata.yrlm)
}
#filter the dataframe by the schools we want to look at
data.gttSchools = unique(data.activeYearsgtt$school)
data.gttSenti = data.raw %>%
filter(school %in% data.gttSchools)
#create an empty dataframe to store the linear models in for plotting
data.schoolLM = data.frame(matrix(ncol = 3, nrow = 0))
colnames(data.schoolLM) <- c("school", "percentLM", "netLM")
# loop over the interested schools using the helper function above
for (school in data.gttSchools) {
data.schoolLM = rbind(data.schoolLM,
PerSchoolSentimentAnalysis(school, data.gttSenti))
}
Joining, by = "word"
Joining, by = "word"
Joining, by = "word"
Joining, by = "word"
Joining, by = "word"
Joining, by = "word"
Joining, by = "word"
Joining, by = "word"
Joining, by = "word"
The following plots were generated for each school (in reverse alpha. order):
Rationalism:

Phenomenology:

Nietzsche:

German Idealism:

Feminism:

Empiricism:

Continental:

Communism:

Capitalism:

Analytic:

Results
The schools with the smallest p values were German Idealism and Feminism at P=0.13 and P=0.08 respectively when regressing against the net positive sentiment. Between the two, only Feminism had an adj R2 greater than 0.95 (next highest was Capitalism at 0.74)
Conclusion
Based on the regression results, we can say that Feminism is the only school that could be considered as having a change in sentiment from going net positive in 1792 to net negative by the latest publication 1981. While capitalism’s regression was the next closest to explaining the data, it’s slope was not far from zero and the sentiment stayed net positive over time.
LS0tDQp0aXRsZTogIkFyeWEgQXlhdGkgUHJvamVjdCAxIFIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpUaGlzIGlzIHRoZSBhY2NvbXBhbnlpbmcgTm90ZWJvb2sgZm9yIG15IHByb2plY3QgMSByZXN1bHRzL2NvZGUuIA0KTXkgcHJvamVjdCBzZWVrZWQgb3V0IHdoZXRoZXIgdGhlIHNlbnRpbWVudCBvZiBhIHNjaG9vbCBjaGFuZ2VkIG92ZXIgdGltZS4gTXkgaHlwb3RoZXNpcyB3YXMgdGhhdCBmb3IgYSBnaXZlbiBzY2hvb2wsIHRoZSBzZW50aW1lbnQgc2hvdWxkIG5vdCBjaGFuZ2UgYmV0d2VlbiB0aGVpciBwdWJsaWNhdGlvbnMgb3ZlciB0aW1lLiBUaGUgdW5kZXJseWluZyBpZGVhIHdhcyB0aGF0IGEgc2Nob29sIGhhcyBhIHNldCBvZiB0aG91Z2h0cyB0aGF0IHRoZXkgZm9sbG93LCBhbmQgdGhhdCB0aGV5IHdvdWxkbid0IGNoYW5nZSB0aGF0IGRyYXN0aWNhbGx5IG92ZXIgdGltZSBzaW5jZSBhbnkgbGFyZ2Ugc2hpZnRzIHdvdWxkIHByb2JhYmx5IHNwcm91dCBhIG5ldyBzY2hvb2wgb2YgdGhvdWdodC4gDQoNCiMjIFN0ZXAgMCAtIEluaXRpYWxpemUgdGhlIGVudmlyb25tZW50DQoNCmBgYHtyfQ0KcGFja2FnZXMudXNlZD1jKCJkcGx5ciIsICJ0aWR5dmVyc2UiLCAidG0iLCAid29yZGNsb3VkIiwgIlJDb2xvckJyZXdlciIsIA0KICAgICAgICAgICAgICAgICJ0aWR5dGV4dCIsICJSY3BwIiwgInRleHRjbGVhbiIsICJnZ2FsdCIsICJnZ3Bsb3QyIiwgImdyaWRFeHRyYSIpDQojIGNoZWNrIHBhY2thZ2VzIHRoYXQgbmVlZCB0byBiZSBpbnN0YWxsZWQuDQpwYWNrYWdlcy5uZWVkZWQ9c2V0ZGlmZihwYWNrYWdlcy51c2VkLCANCiAgICAgICAgICAgICAgICAgICAgICAgIGludGVyc2VjdChpbnN0YWxsZWQucGFja2FnZXMoKVssMV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhY2thZ2VzLnVzZWQpKQ0KIyBpbnN0YWxsIGFkZGl0aW9uYWwgcGFja2FnZXMNCmlmKGxlbmd0aChwYWNrYWdlcy5uZWVkZWQpPjApew0KICBpbnN0YWxsLnBhY2thZ2VzKHBhY2thZ2VzLm5lZWRlZCwgZGVwZW5kZW5jaWVzID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICByZXBvcz0naHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZycpDQp9DQoNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkodG0pDQpsaWJyYXJ5KHdvcmRjbG91ZCkNCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KbGlicmFyeSh0aWR5dGV4dCkNCmxpYnJhcnkoUmNwcCkNCmxpYnJhcnkodGV4dGNsZWFuKQ0KbGlicmFyeShnZ2FsdCkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZ3JpZEV4dHJhKQ0Kc2V0d2QoIk06L0RvY3VtZW50cy9DVSBDb3Vyc2V3b3JrL1NUQVQ1MjQzIEFwcGxpZWQgRGF0YSBTY2llbmNlL1Byb2plY3RzL0ZhbGwyMDIxLVByb2plY3QxLUFyeWFBeWF0aSIpDQpgYGANClRoZSBub3RlYm9vayB3YXMgcHJlcGFyZWQgd2l0aCB0aGUgZm9sbG93aW5nIGVudmlyb25tZW50YWwgc2V0dGluZ3MuIA0KYGBge3J9DQpwcmludChSLnZlcnNpb24pDQpgYGANCiMjIFN0ZXAgMSAtIFJlYWQgaW4gdGhlIHBoaWxvc29waHkgZGF0YSBhbmQgY2hlY2sgdGhlIGZvcm1hdHRpbmcNCmBgYHtyfQ0KZGF0YS5yYXcgPSByZWFkLmNzdignZGF0YS9waGlsb3NvcGh5X2RhdGEuY3N2JykNCmBgYA0KYGBge3J9DQpjb2xuYW1lcyhkYXRhLnJhdykNCmBgYA0KYGBge3J9DQp1bmlxdWUoZGF0YS5yYXckYXV0aG9yKQ0KYGBgDQpgYGB7cn0NCnVuaXF1ZShkYXRhLnJhdyRzY2hvb2wpDQpgYGANCmBgYHtyfQ0Kc3VtbWFyeShkYXRhLnJhdyRvcmlnaW5hbF9wdWJsaWNhdGlvbl9kYXRlKQ0KYGBgDQpgYGB7cn0NCnN1bW1hcnkodW5pcXVlKGRhdGEucmF3JHRpdGxlKSkNCmBgYA0KVGhlIGRhdGEgY29udGFpbnMgNTkgdGl0bGVzIGZvciAxMyBzY2hvb2xzIG9mIHRob3VnaHQgc28gd2UgY2FuIGV4cGVjdCBlbm91Z2ggZGF0YXBvaW50cyB0byBydW4gYSByZWdyZXNzaW9uIG9uIG1vc3Qgc2Nob29scy4gDQoNCiMjIFN0ZXAgMiAtIFRleHQgcHJvY2Vzc2luZw0KYGBge3J9DQpzZW50ZW5jZUNvcnB1cyA8LSBDb3JwdXMoVmVjdG9yU291cmNlKGRhdGEucmF3JHNlbnRlbmNlX2xvd2VyZWQpKQ0Kc2VudGVuY2VDb3JwdXM8LXRtX21hcChzZW50ZW5jZUNvcnB1cywgcmVtb3ZlV29yZHMsIHN0b3B3b3JkcygiZW5nbGlzaCIpKQ0Kc2VudGVuY2VDb3JwdXM8LXRtX21hcChzZW50ZW5jZUNvcnB1cywgcmVtb3ZlV29yZHMsIGNoYXJhY3RlcigwKSkNCnNlbnRlbmNlQ29ycHVzPC10bV9tYXAoc2VudGVuY2VDb3JwdXMsIHJlbW92ZVB1bmN0dWF0aW9uKQ0Kc2VudGVuY2VDb3JwdXM8LXRtX21hcChzZW50ZW5jZUNvcnB1cywgc3RyaXBXaGl0ZXNwYWNlKQ0KDQp0ZG0gPC0gVGVybURvY3VtZW50TWF0cml4KHNlbnRlbmNlQ29ycHVzKQ0KdGRtID0gcmVtb3ZlU3BhcnNlVGVybXModGRtLCAwLjk5KQ0KdGRtLnRpZHkgPSB0aWR5dGV4dDo6dGlkeSh0ZG0pDQp0ZG0ub3ZlcmFsbD1zdW1tYXJpc2UoZ3JvdXBfYnkodGRtLnRpZHksIHRlcm0pLCBzdW0oY291bnQpKQ0KYGBgDQojIyBTdGVwIDMgLSBPdmVyYWxsIHdvcmRjbG91ZCBpbnNwZWN0aW9uDQpHZW5lcmF0aW5nIGEgd29yZGNsb3VkIG9mIHRoZSBEb2N1bWVudCBUZXJtIE1hdHJpeCBjbGVhbmVkIG9mIHN0b3B3b3JkcyBhbmQgb3RoZXIgbm9uLXdvcmQgIGNoYXJhY3RlcnMgeWllbGRlZCB0aGUgZm9sbG93aW5nOg0KIVtdKE06L0RvY3VtZW50cy9DVSBDb3Vyc2V3b3JrL1NUQVQ1MjQzIEFwcGxpZWQgRGF0YSBTY2llbmNlL1Byb2plY3RzL0ZhbGwyMDIxLVByb2plY3QxLUFyeWFBeWF0aS9maWdzL0Jhc2VfQ2xlYW5lZF9XQy5wbmcpDQpPdmVyYWxsLCB0aGUgdGVybXMgc2VlbSBub3JtYWwgZm9yIHBoaWxvc29waGljYWwgdGV4dHMgYW5kIGNvbmZpcm0gdGhhdCB3ZSBoYXZlIGFwcHJvcHJpYXRlIGRhdGEuIEdlbmVyYXRpbmcgYW5vdGhlciB3b3JkY2xvdWQgdXNpbmcgVEYtSURGIHlpZWxkZWQgdGhlIGZvbGxvd2luZzoNCiFbXShNOi9Eb2N1bWVudHMvQ1UgQ291cnNld29yay9TVEFUNTI0MyBBcHBsaWVkIERhdGEgU2NpZW5jZS9Qcm9qZWN0cy9GYWxsMjAyMS1Qcm9qZWN0MS1BcnlhQXlhdGkvZmlncy9URklERl9vdmVyYWxsX1dDLnBuZykNClRoZSBURi1JREYgd29yZGNsb3VkIGlzIHByZXR0eSBzaW1pbGFyIHRvIHRoZSBvcmlnaW5hbCB3aGljaCBsZWFkcyBtZSB0byBiZWxpZXZlIHRoYXQgc29tZXRoaW5nIHdlbnQgd3JvbmcgYWxvbmcgdGhlIHdheS4gTHVja2lseSwgdGhpcyB3YXMgcHJpbWFyaWx5IGFuIGV4Y2VyY2lzZSB0byBleHBsb3JlIHRoZSBmb3JtYXQgb2YgdGhlIGRhdGEgYW5kIGlzIG5vdCByZWxldmFudCB0byB0aGUgaHlwb3RoZXNpcyB0ZXN0aW5nLiANCg0KIyMgU3RlcCA0IC0gR3JvdXBpbmcgcHVibGljYXRpb25zIGJ5IHllYXIgdG8gYW5hbHl6ZSByZWdyZXNzYWJpbGl0eQ0KDQpgYGB7cix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZWNobyA9IEZBTFNFfQ0KZGF0YS5hY3RpdmVZZWFycyA9IGRhdGEucmF3ICU+JQ0KICBzZWxlY3QoYygxOjMsNikpICU+JQ0KICBncm91cF9ieSh0aXRsZSwgc2Nob29sLCBvcmlnaW5hbF9wdWJsaWNhdGlvbl9kYXRlKSAlPiUNCiAgc3VtbWFyaXNlKCkgJT4lDQogIGdyb3VwX2J5KHNjaG9vbCwgb3JpZ2luYWxfcHVibGljYXRpb25fZGF0ZSkgJT4lDQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lDQogIG11dGF0ZShjb3VudCA9IGFzLmZhY3Rvcihjb3VudCkpDQpgYGANCg0KUGxvdHRpbmcgdGhlIHB1YmxpY2F0aW9ucyBvdmVyIHRpbWUgdG8gc2VlIGlmIHRoZXJlIGFyZSBlbm91Z2ggZGF0YXBvaW50cyBiZXR3ZWVuIHRoZSBzY2hvb2xzIHRvIG1ha2UgdGhlIGFuYWx5c2lzIHdvcnRod2hpbGUgeWllbGRzOg0KIVtdKE06L0RvY3VtZW50cy9DVSBDb3Vyc2V3b3JrL1NUQVQ1MjQzIEFwcGxpZWQgRGF0YSBTY2llbmNlL1Byb2plY3RzL0ZhbGwyMDIxLVByb2plY3QxLUFyeWFBeWF0aS9maWdzL1B1YlRpbWVfQWxsLnBuZykNCg0KYGBge3Isd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVjaG8gPSBGQUxTRX0NCmRhdGEuYWN0aXZlWWVhcnNndHQgPSBkYXRhLmFjdGl2ZVllYXJzICU+JQ0KICBncm91cF9ieShzY2hvb2wpICU+JQ0KICBmaWx0ZXIobigpID4gMikNCmBgYA0KDQpGaWx0ZXJpbmcgdGhlIHNjaG9vbHMgb2YgdGhvdWdodCB0byB0aG9zZSB3aXRoIDMgb3IgbW9yZSBwdWJsaWNhdGlvbnMgLSBzbyB0aGF0IGEgcmVncmVzc2lvbiBpcyBub250cml2aWFsIC0geWllbGRlZCB0aGUgZm9sbG93aW5nIHBsb3Q6DQohW10oTTovRG9jdW1lbnRzL0NVIENvdXJzZXdvcmsvU1RBVDUyNDMgQXBwbGllZCBEYXRhIFNjaWVuY2UvUHJvamVjdHMvRmFsbDIwMjEtUHJvamVjdDEtQXJ5YUF5YXRpL2ZpZ3MvUHViVGltZV9HVFQucG5nKQ0KRnJvbSBoZXJlLCBtb3N0IG9mIHRoZSByZW1haW5pbmcgc2Nob29scyBzaG91bGQgaGF2ZSBlbm91Z2ggZGF0YXBvaW50cyB0byBhdHRlbXB0IHRvIGZpdCBsaW5lYXIgbW9kZWxzIHRvIHRoZW0gYW5kIGRldGVybWluZSBpZiBub256ZXJvIGNvZWZmaWNpZW50cyBhcmUgc2lnbmlmaWNhbnQgb3Igbm90LiANCg0KIyMgU3RlcCA1IC0gTG9vcCB0aHJvdWdoIHRoZSByZW1haW5pbmcgc2Nob29scyBhbmQgcGVyZm9ybSByZWdyZXNzaW9ucyB0byB0ZXN0IGh5cG90aGVzaXMNCmBgYHtyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlY2hvID0gVFJVRX0NCiNTZW50aW1lbnQgQW5hbHlzaXMgcGVyIHNjaG9vbCB1c2luZyBoZWxwZXIgZnVuY3Rpb246DQpQZXJTY2hvb2xTZW50aW1lbnRBbmFseXNpcyA8LSBmdW5jdGlvbihzY2gsIGRhdGEuZ3R0U2VudGkpIHsNCiAgc2Nob29sZGF0YS5yYXcgPSBkYXRhLmd0dFNlbnRpW2RhdGEuZ3R0U2VudGkkc2Nob29sPT1zY2gsXQ0KICANCiAgeWVhcnMgPSB1bmlxdWUoc2Nob29sZGF0YS5yYXckb3JpZ2luYWxfcHVibGljYXRpb25fZGF0ZSkNCiAgc2Nob29sZGF0YS5TZW50aSA9IGRhdGEuZnJhbWUobWF0cml4KG5jb2wgPSA1LCBucm93ID0gMCkpDQogIGNvbG5hbWVzKHNjaG9vbGRhdGEuU2VudGkpIDwtIGMoInllYXIiLCAibmVnYXRpdmUiLCAicG9zaXRpdmUiLCAic2VudGltZW50IiwgIm5ldFNlbnRpIikNCiAgDQogIGZvciAoaSBpbiB5ZWFycyl7DQogICAgI3BlciBwdWJsaWNhdGlvbiBzZW50aW1lbnQNCiAgICBzY2hvb2xkYXRhLnRlbXB0eHQgPSBzY2hvb2xkYXRhLnJhdyAlPiUNCiAgICAgIGZpbHRlcihvcmlnaW5hbF9wdWJsaWNhdGlvbl9kYXRlID09IGkpDQogICAgc2Nob29sZGF0YS55clRva2VucyA9IGRhdGFfZnJhbWUodG9rZW5zID0gc2Nob29sZGF0YS50ZW1wdHh0JHRva2VuaXplZF90eHQpICU+JSANCiAgICAgIHVubmVzdF90b2tlbnMod29yZCwgdG9rZW5zKQ0KICAjcmVmZXJlbmNlIGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy90aWR5dGV4dC92aWduZXR0ZXMvdGlkeXRleHQuaHRtbA0KICAgIHNjaG9vbGRhdGEudG1wU2VudGkgPSBzY2hvb2xkYXRhLnlyVG9rZW5zICU+JSANCiAgICAgIGlubmVyX2pvaW4oZ2V0X3NlbnRpbWVudHMoImJpbmciKSkgJT4lIA0KICAgICAgY291bnQoc2VudGltZW50KSAlPiUgDQogICAgICBzcHJlYWQoc2VudGltZW50LCBuLCBmaWxsID0gMCkgJT4lDQogICAgICBtdXRhdGUoc2VudGltZW50ID0gcG9zaXRpdmUgLyAocG9zaXRpdmUgKyBuZWdhdGl2ZSksIG5ldFNlbnRpID0gcG9zaXRpdmUtbmVnYXRpdmUpDQogICAgc2Nob29sZGF0YS55clNlbnRpID0gY2JpbmQoZGF0YV9mcmFtZSh5ZWFyID0gaSksIHNjaG9vbGRhdGEudG1wU2VudGkpDQogICAgc2Nob29sZGF0YS5TZW50aSA9IHJiaW5kKHNjaG9vbGRhdGEuU2VudGksIHNjaG9vbGRhdGEueXJTZW50aSkNCiAgfQ0KICBwZXJjTE0gPSBsbShzZW50aW1lbnR+eWVhciwgZGF0YSA9IHNjaG9vbGRhdGEuU2VudGkpDQogIG5ldExNID0gbG0obmV0U2VudGl+eWVhciwgZGF0YSA9IHNjaG9vbGRhdGEuU2VudGkpDQogIA0KICBwZXJjUGxvdCA9IGdncGxvdChkYXRhID0gc2Nob29sZGF0YS5TZW50aSwgYWVzKHg9eWVhciwgeT1zZW50aW1lbnQpKSArIA0KICAgIGdlb21fcG9pbnQoY29sb3I9J2JsdWUnKSArDQogICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBUUlVFLCBmb3JtdWxhID0geX54KSsNCiAgICBsYWJzKHN1YnRpdGxlID0gcGFzdGUoIkFkaiBSMiA9ICIsc2lnbmlmKHN1bW1hcnkocGVyY0xNKSRhZGouci5zcXVhcmVkLCA1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgIkludGVyY2VwdCA9IixzaWduaWYocGVyY0xNJGNvZWZbWzFdXSw1ICksDQogICAgICAgICAgICAgICAgICAgICAgICIgU2xvcGUgPSIsc2lnbmlmKHBlcmNMTSRjb2VmW1syXV0sIDUpLA0KICAgICAgICAgICAgICAgICAgICAgICAiIFAgPSIsc2lnbmlmKHN1bW1hcnkocGVyY0xNKSRjb2VmWzIsNF0sIDUpKSkrDQogICAgZ2d0aXRsZShwYXN0ZSgiU2VudGltZW50IGJ5IFllYXIgZm9yIiwgc3RyX3RvX3RpdGxlKHNjaCkpKSsNCiAgICB4bGFiKCJZZWFyIikrDQogICAgeWxhYigiUG9zaXRpdmUgU2VudGltZW50IFBlcmNlbnQiKSsNCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCiAgbmV0UGxvdCA9IGdncGxvdChkYXRhID0gc2Nob29sZGF0YS5TZW50aSwgYWVzKHg9eWVhciwgeT1uZXRTZW50aSkpICsgDQogICAgZ2VvbV9wb2ludChjb2xvcj0nYmx1ZScpICsNCiAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IFRSVUUsIGZvcm11bGEgPSB5fngpKw0KICAgIGxhYnMoc3VidGl0bGUgPSBwYXN0ZSgiQWRqIFIyID0gIixzaWduaWYoc3VtbWFyeShuZXRMTSkkYWRqLnIuc3F1YXJlZCwgNSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICJJbnRlcmNlcHQgPSIsc2lnbmlmKG5ldExNJGNvZWZbWzFdXSw1ICksDQogICAgICAgICAgICAgICAgICAgICAgICAgICIgU2xvcGUgPSIsc2lnbmlmKG5ldExNJGNvZWZbWzJdXSwgNSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICIgUCA9IixzaWduaWYoc3VtbWFyeShuZXRMTSkkY29lZlsyLDRdLCA1KSkpKw0KICAgIGdndGl0bGUocGFzdGUoIlNlbnRpbWVudCBieSBZZWFyIGZvciIsIHN0cl90b190aXRsZShzY2gpKSkrDQogICAgeGxhYigiWWVhciIpKw0KICAgIHlsYWIoIk5ldCBQb3NpdGl2ZSBTZW50aW1lbnQiKSsNCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCiAgDQogIHBuZyhwYXN0ZSgiZmlncy8iLCBzY2gsICJfcGxvdHMucG5nIiwgc2VwPSIiKSwgdW5pdHM9ImluIiwgd2lkdGg9MTIsIGhlaWdodD01LCByZXM9NjAwKQ0KICBncmlkLmFycmFuZ2UocGVyY1Bsb3QsIG5ldFBsb3QsIG5jb2w9MikNCiAgZGV2Lm9mZigpDQogIA0KICAjSW5zZXJ0IHBsb3RzIGhlcmUgaW4gbWFya2Rvd24NCiAgDQogICNzYXZlIHJlZ3Jlc3Npb24gc3VtbWFyaWVzIGZvciBsYXRlcg0KICBzY2hvb2xkYXRhLnlybG0gPSBjYmluZChkYXRhX2ZyYW1lKHNjaG9vbCA9IHNjaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGFfZnJhbWUobGlzdChwZXJjTE0pKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YV9mcmFtZShsaXN0KG5ldExNKSkpDQogIGNvbG5hbWVzKHNjaG9vbGRhdGEueXJsbSkgPC0gYygic2Nob29sIiwgInBlcmNlbnRMTSIsICJuZXRMTSIpDQogIHJldHVybihzY2hvb2xkYXRhLnlybG0pDQp9DQpgYGANCg0KDQpgYGB7cix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZWNobyA9IFRSVUV9DQojZmlsdGVyIHRoZSBkYXRhZnJhbWUgYnkgdGhlIHNjaG9vbHMgd2Ugd2FudCB0byBsb29rIGF0DQpkYXRhLmd0dFNjaG9vbHMgPSB1bmlxdWUoZGF0YS5hY3RpdmVZZWFyc2d0dCRzY2hvb2wpDQpkYXRhLmd0dFNlbnRpID0gZGF0YS5yYXcgJT4lDQogIGZpbHRlcihzY2hvb2wgJWluJSBkYXRhLmd0dFNjaG9vbHMpDQoNCiNjcmVhdGUgYW4gZW1wdHkgZGF0YWZyYW1lIHRvIHN0b3JlIHRoZSBsaW5lYXIgbW9kZWxzIGluIGZvciBwbG90dGluZw0KZGF0YS5zY2hvb2xMTSA9IGRhdGEuZnJhbWUobWF0cml4KG5jb2wgPSAzLCBucm93ID0gMCkpDQpjb2xuYW1lcyhkYXRhLnNjaG9vbExNKSA8LSBjKCJzY2hvb2wiLCAicGVyY2VudExNIiwgIm5ldExNIikNCg0KIyBsb29wIG92ZXIgdGhlIGludGVyZXN0ZWQgc2Nob29scyB1c2luZyB0aGUgaGVscGVyIGZ1bmN0aW9uIGFib3ZlDQpmb3IgKHNjaG9vbCBpbiBkYXRhLmd0dFNjaG9vbHMpIHsNCiAgZGF0YS5zY2hvb2xMTSA9IHJiaW5kKGRhdGEuc2Nob29sTE0sDQogICAgICAgICAgICAgICAgICAgICAgICBQZXJTY2hvb2xTZW50aW1lbnRBbmFseXNpcyhzY2hvb2wsIGRhdGEuZ3R0U2VudGkpKQ0KfQ0KDQpgYGANClRoZSBmb2xsb3dpbmcgcGxvdHMgd2VyZSBnZW5lcmF0ZWQgZm9yIGVhY2ggc2Nob29sIChpbiByZXZlcnNlIGFscGhhLiBvcmRlcik6DQoNCiMjIyMgUmF0aW9uYWxpc206DQoNCiFbXShNOi9Eb2N1bWVudHMvQ1UgQ291cnNld29yay9TVEFUNTI0MyBBcHBsaWVkIERhdGEgU2NpZW5jZS9Qcm9qZWN0cy9GYWxsMjAyMS1Qcm9qZWN0MS1BcnlhQXlhdGkvZmlncy9yYXRpb25hbGlzbV9wbG90cy5wbmcpDQoNCiMjIyMgUGhlbm9tZW5vbG9neToNCg0KIVtdKE06L0RvY3VtZW50cy9DVSBDb3Vyc2V3b3JrL1NUQVQ1MjQzIEFwcGxpZWQgRGF0YSBTY2llbmNlL1Byb2plY3RzL0ZhbGwyMDIxLVByb2plY3QxLUFyeWFBeWF0aS9maWdzL3BoZW5vbWVub2xvZ3lfcGxvdHMucG5nKQ0KDQojIyMjIE5pZXR6c2NoZToNCg0KIVtdKE06L0RvY3VtZW50cy9DVSBDb3Vyc2V3b3JrL1NUQVQ1MjQzIEFwcGxpZWQgRGF0YSBTY2llbmNlL1Byb2plY3RzL0ZhbGwyMDIxLVByb2plY3QxLUFyeWFBeWF0aS9maWdzL25pZXR6c2NoZV9wbG90cy5wbmcpDQoNCiMjIyMgR2VybWFuIElkZWFsaXNtOg0KDQohW10oTTovRG9jdW1lbnRzL0NVIENvdXJzZXdvcmsvU1RBVDUyNDMgQXBwbGllZCBEYXRhIFNjaWVuY2UvUHJvamVjdHMvRmFsbDIwMjEtUHJvamVjdDEtQXJ5YUF5YXRpL2ZpZ3MvZ2VybWFuX2lkZWFsaXNtX3Bsb3RzLnBuZykNCg0KIyMjIyBGZW1pbmlzbToNCg0KIVtdKE06L0RvY3VtZW50cy9DVSBDb3Vyc2V3b3JrL1NUQVQ1MjQzIEFwcGxpZWQgRGF0YSBTY2llbmNlL1Byb2plY3RzL0ZhbGwyMDIxLVByb2plY3QxLUFyeWFBeWF0aS9maWdzL2ZlbWluaXNtX3Bsb3RzLnBuZykNCg0KIyMjIyBFbXBpcmljaXNtOg0KDQohW10oTTovRG9jdW1lbnRzL0NVIENvdXJzZXdvcmsvU1RBVDUyNDMgQXBwbGllZCBEYXRhIFNjaWVuY2UvUHJvamVjdHMvRmFsbDIwMjEtUHJvamVjdDEtQXJ5YUF5YXRpL2ZpZ3MvZW1waXJpY2lzbV9wbG90cy5wbmcpDQoNCiMjIyMgQ29udGluZW50YWw6DQoNCiFbXShNOi9Eb2N1bWVudHMvQ1UgQ291cnNld29yay9TVEFUNTI0MyBBcHBsaWVkIERhdGEgU2NpZW5jZS9Qcm9qZWN0cy9GYWxsMjAyMS1Qcm9qZWN0MS1BcnlhQXlhdGkvZmlncy9jb250aW5lbnRhbF9wbG90cy5wbmcpDQoNCiMjIyMgQ29tbXVuaXNtOg0KDQohW10oTTovRG9jdW1lbnRzL0NVIENvdXJzZXdvcmsvU1RBVDUyNDMgQXBwbGllZCBEYXRhIFNjaWVuY2UvUHJvamVjdHMvRmFsbDIwMjEtUHJvamVjdDEtQXJ5YUF5YXRpL2ZpZ3MvY29tbXVuaXNtX3Bsb3RzLnBuZykNCg0KIyMjIyBDYXBpdGFsaXNtOg0KDQohW10oTTovRG9jdW1lbnRzL0NVIENvdXJzZXdvcmsvU1RBVDUyNDMgQXBwbGllZCBEYXRhIFNjaWVuY2UvUHJvamVjdHMvRmFsbDIwMjEtUHJvamVjdDEtQXJ5YUF5YXRpL2ZpZ3MvY2FwaXRhbGlzbV9wbG90cy5wbmcpDQoNCiMjIyMgQW5hbHl0aWM6DQoNCiFbXShNOi9Eb2N1bWVudHMvQ1UgQ291cnNld29yay9TVEFUNTI0MyBBcHBsaWVkIERhdGEgU2NpZW5jZS9Qcm9qZWN0cy9GYWxsMjAyMS1Qcm9qZWN0MS1BcnlhQXlhdGkvZmlncy9hbmFseXRpY19wbG90cy5wbmcpDQoNCiMjIFJlc3VsdHMNCg0KVGhlIHNjaG9vbHMgd2l0aCB0aGUgc21hbGxlc3QgcCB2YWx1ZXMgd2VyZSBHZXJtYW4gSWRlYWxpc20gYW5kIEZlbWluaXNtIGF0IFA9MC4xMyBhbmQgUD0wLjA4IHJlc3BlY3RpdmVseSB3aGVuIHJlZ3Jlc3NpbmcgYWdhaW5zdCB0aGUgbmV0IHBvc2l0aXZlIHNlbnRpbWVudC4gQmV0d2VlbiB0aGUgdHdvLCBvbmx5IEZlbWluaXNtIGhhZCBhbiBhZGogUjIgZ3JlYXRlciB0aGFuIDAuOTUgKG5leHQgaGlnaGVzdCB3YXMgQ2FwaXRhbGlzbSBhdCAwLjc0KSANCg0KIyMgQ29uY2x1c2lvbg0KDQpCYXNlZCBvbiB0aGUgcmVncmVzc2lvbiByZXN1bHRzLCB3ZSBjYW4gc2F5IHRoYXQgRmVtaW5pc20gaXMgdGhlIG9ubHkgc2Nob29sIHRoYXQgY291bGQgYmUgY29uc2lkZXJlZCBhcyBoYXZpbmcgYSBjaGFuZ2UgaW4gc2VudGltZW50IGZyb20gZ29pbmcgbmV0IHBvc2l0aXZlIGluIDE3OTIgdG8gbmV0IG5lZ2F0aXZlIGJ5IHRoZSBsYXRlc3QgcHVibGljYXRpb24gMTk4MS4gV2hpbGUgY2FwaXRhbGlzbSdzIHJlZ3Jlc3Npb24gd2FzIHRoZSBuZXh0IGNsb3Nlc3QgdG8gZXhwbGFpbmluZyB0aGUgZGF0YSwgaXQncyBzbG9wZSB3YXMgbm90IGZhciBmcm9tIHplcm8gYW5kIHRoZSBzZW50aW1lbnQgc3RheWVkIG5ldCBwb3NpdGl2ZSBvdmVyIHRpbWUuIA==